﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using TCC_Hotel.Entidades;
using TCC_Hotel.Repositorio;
using System.Web.Caching;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;
using System.Configuration;
using System.IO;
using System.Data;
using TCC_Hotel.Serviços.OtherServices;

namespace TCC_Hotel.Serviços.BDServices
{
    public class FluxoHospedesService : System.Web.UI.Page
    {
        FluxoHospedesRepositorio repositorio = new FluxoHospedesRepositorio();
        ReservaService servico_Reserva = new ReservaService();
        ApartamentoService servico_Apartamento = new ApartamentoService();
        GeralServices sericos_Gerais = new GeralServices();
        ContaService servico_Conta = new ContaService();

        /// <summary>
        /// Serviço para incluir novos hospedes no hotel
        /// </summary>
        /// <param name="funcionario">hospedes que entraram</param>
        /// <returns>True se foi inserido ou false se nao</returns>
        public bool EfetuarCheckIn(Fluxo_Hospedes fluxo)
        {
            TimeSpan tempo;
            //calcula o numero d diarias
            if (fluxo.Data_Saida.Date == fluxo.Data_Entrada.Date)
            {
                tempo = fluxo.Data_Saida.AddDays(1).Date - fluxo.Data_Entrada.Date;
            }
            else
            {
                tempo = fluxo.Data_Saida.Date - fluxo.Data_Entrada.Date;
            }

            //calcula quantidade de hospedes           
            int numeroHospedes = QuantidadeHospedes(fluxo);
            double preco_Diaria = sericos_Gerais.RecuperarPrecoDiaria(numeroHospedes);
            bool pagamento = true;

            if (fluxo.ID % 2 != 0)
            {
                pagamento = false;
            }

            //prepara o objeto conta para o hospede dizendo que ele pagou as diarias
            Conta conta = new Conta()
            {
                ID = fluxo.ID,
                Descricao = "Pagamento de " + tempo.Days + " diárias para " + numeroHospedes + " hóspedes",
                Preco = preco_Diaria * tempo.Days,
                Pagamento = pagamento,
                Data = DateTime.Now

            };

            return repositorio.EfetuarCheckIn(fluxo, conta);
        }
        
        
        /// <summary>
        /// Serviço para alterar o celular de um fluxo
        /// </summary>
        /// <param name="funcionario">fluxo atualizado</param>
        /// <returns>True se foi alterado ou false se nao</returns>
        public bool AlterarCelularSMS(Fluxo_Hospedes fluxo)
        {
            return repositorio.AlterarCelularSMS(fluxo);
        }

        /// <summary>
        /// Serviço para calcular preço da entrada
        /// </summary>
        /// <param name="funcionario">hospedes que entraram</param>
        /// <returns>True se foi inserido ou false se nao</returns>
        public double CalcularPrecoEntrada(Fluxo_Hospedes fluxo)
        {
            TimeSpan tempo;
            //calcula o numero d diarias            
           tempo = fluxo.Data_Reserva_Saida.AddDays(1).Date - fluxo.Data_Reserva_Entrada.Date;           
           
            //calcula quantidade de hospedes           
            int numeroHospedes = QuantidadeHospedes(fluxo);
            double preco_Diaria = sericos_Gerais.RecuperarPrecoDiaria(numeroHospedes);

            return preco_Diaria * tempo.Days;
        }


        /// <summary>
        /// Serviço para extender a estadia de um hospede no hotel
        /// </summary>
        /// <param name="funcionario">hospedes que iram extenter sua estadia</param>
        /// <returns>True se foi extendida ou false se nao</returns>
        public bool ExtenderEstadia(int ID, DateTime novaData)
        {
            GeralServices servico_Geral = new GeralServices();

            //recupera o fluxo hospede corrente
            Fluxo_Hospedes fluxo = ListarFluxoHospedesAgoraCache().Where(i => i.ID == ID).FirstOrDefault();
            int numeroHospedes = QuantidadeHospedes(fluxo);

            //calcula o numero d diarias
            TimeSpan diariasMais = novaData - fluxo.Data_Saida;

            //calcula preco a ser pago para extender a estadia
            double precoMais = servico_Geral.RecuperarPrecoDiariaCache(numeroHospedes) * diariasMais.Days;
            bool pagamento = true;

            if (ID % 2 != 0)
            {
                pagamento = false;
            }
            //prepara o objeto conta para o hospede dizendo que ele pagou as diarias
            Conta conta = new Conta()
            {
                ID = fluxo.ID,
                Descricao = "Pagamento de " + diariasMais.Days + " diárias a mais para " + numeroHospedes + " hóspedes",
                Preco = precoMais,
                Pagamento = pagamento,
                Data = DateTime.Now
            };

            fluxo.Data_Saida = novaData;
            return repositorio.ExtenderEstadia(fluxo, conta);
        }

        /// <summary>
        /// Serviço para gera uma nova diaria para um hospede no hotel
        /// </summary>
        /// <param name="funcionario">hospedes que iram extenter sua estadia</param>
        /// <returns>True se foi extendida ou false se nao</returns>
        public bool GerarNovaDiaria(int ID, DateTime novaData)
        {
            ReservaService servico_Reserva = new ReservaService();

            List<Reserva_Particular> listaReservas_Particulares;
            List<Reserva_Faturada> listaReservas_Faturadas;
            List<DiaNomeReserva> listaDiasReservas;

            //recupera o fluxo hospede corrente
            Fluxo_Hospedes fluxo = RecuperarFluxoHospedesAgora().Where(i => i.ID == ID).FirstOrDefault();
            int numeroHospedes = QuantidadeHospedes(fluxo);

            listaReservas_Particulares = servico_Reserva.RecuperarReservasParticularesApartamento(Convert.ToInt32(fluxo.Numero_Apartamento));
            listaReservas_Faturadas = servico_Reserva.RecuperarReservasFaturadasApartamento(Convert.ToInt32(fluxo.Numero_Apartamento));
            listaDiasReservas = servico_Reserva.ListarDiasReservas(listaReservas_Particulares, listaReservas_Faturadas);

            bool disponivel = servico_Reserva.VerificaDisponibilidade(DateTime.Today.ToString(), DateTime.Today.ToString(), listaDiasReservas);

            GeralServices servico_Geral = new GeralServices();

            if (disponivel)
            {
                //calcula o numero d diarias
                TimeSpan diariasMais = novaData - fluxo.Data_Saida;

                //calcula preco a ser pago para extender a estadia
                double precoMais = servico_Geral.RecuperarPrecoDiaria(numeroHospedes) * diariasMais.Days;
                bool pagamento = false;
                string msg;

                if (diariasMais.Days == 1)
                {
                    msg = " diária a mais gerada automaticamente";
                }
                else
                {
                    msg = " diárias a mais geradas automaticamente";
                }
                //prepara o objeto conta para o hospede dizendo que ele pagou as diarias
                Conta conta = new Conta()
                {
                    ID = fluxo.ID,
                    Descricao = diariasMais.Days + msg,
                    Preco = precoMais,
                    Pagamento = pagamento,
                    Data = DateTime.Now
                };

                fluxo.Data_Saida = novaData;
                return repositorio.ExtenderEstadiaAgenda(fluxo, conta);
            }

            return false;
        }

        /// <summary>
        /// Cria o comando SQL e envia para um método de fazer o checkOut de hospedes do hotel
        /// </summary>
        /// <param name="hospedes">Entidade Fluxo_Hospedes</param>
        /// <returns>true se inseriu ou false se não</returns>
        public bool EfetuarCheckOut(string ID_Reserva, string Apartamento)
        {
            int ID_Res = Convert.ToInt32(ID_Reserva);
            double totalConta = servico_Conta.RecuperarTotalConta(ID_Res);

            //recupera o fluxo hospede corrente
            Fluxo_Hospedes fluxo = RecuperarFluxoHospedesAgora().Where(i => i.ID == ID_Res).FirstOrDefault();
            

            //Faz um objeto fluxo_hospede que sera editado com as configurações de check-out
            Fluxo_Hospedes hospedes = new Fluxo_Hospedes()
            {
                ID = ID_Res,
                Data_Saida = DateTime.Now,
                NoHotel = false,
                Preco_Total = totalConta
            };

            double totalContaPaga = servico_Conta.RecuperarTotalContaPagaCheckOut(ID_Res);
            //Faz um objeto para ser guardado na tabela de balanço financeiro
            Balanco_Financeiro balanco = new Balanco_Financeiro()
            {
                Descricao = "Check-out do hospede " + fluxo.Nome_1 + " do apartamento número ",
                PrecoGasto = totalContaPaga,
                Receita = true,
                DataDespesa = DateTime.Now
            };

            bool resposta;
            if (ID_Res % 2 != 0)
            {
                //chama o método para enviar o email com a fatura dos hospedes faturados
                if (GerarContaEnviarEmail(ID_Res))
                    resposta = repositorio.EfetuarCheckOut(hospedes, balanco);
                else
                    resposta = false;
            }
            else
            {
                resposta = repositorio.EfetuarCheckOut(hospedes, balanco);
            }
            return resposta;
        }

        /// <summary>
        /// Método que gera a conta para enviar para a empresa do hóspede
        /// </summary>
        /// <param name="ID_Fluxo"></param>
        public bool GerarContaEnviarEmail(int ID_Fluxo)
        {
            ReportDocument report = new ReportDocument();

            //recupera o fluxo corrente
            Fluxo_Hospedes fluxo = RecuperarDetalhesFluxoHospede(ID_Fluxo);

            //Carrega o relatório elaborado
            report.Load(Server.MapPath("~\\Apresentacao\\FluxoHospedesAgora\\CrystalReportContaEmpresa.rpt"));

            report.SetParameterValue("ID_Reserva", fluxo.ID);
            report.SetParameterValue("Apartamento", fluxo.Numero_Apartamento);
            report.SetParameterValue("CheckIn", fluxo.Data_Entrada.ToString());
            report.SetParameterValue("CheckOut", DateTime.Now.ToString());
            report.SetParameterValue("CheckInReserva", fluxo.Data_Entrada.ToString().Substring(0, 10));
            report.SetParameterValue("CheckOutReserva", fluxo.Data_Saida.ToString().Substring(0, 10));


            //Faz loggin no CrystalReports
            LogginCrystalReports(report);

            // utilizando o ExportToStream. 
            System.IO.Stream st = report.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat);

            // criar um Leitor de Binários para receber o stream 
            System.IO.BinaryReader br = new System.IO.BinaryReader(st);

            // cria um vetor de bytes do tamanho do stream 
            byte[] vet = new byte[st.Length];

            // Carrega o vetor de bytes 
            for (int x = 0; x < (st.Length); ++x)
                vet[x] = br.ReadByte();

            MemoryStream memoria = new MemoryStream(vet);

            //inicializa os serviços necessarios para adquirir o email da empresa e anviar o email
            ExternalService servico_Email = new ExternalService();
            EmpresaService servico_Empresa = new EmpresaService();
            ReservaService servico_Reserva = new ReservaService();

            //recupera o email da empresa
            string cnpj = servico_Reserva.RecuperarDetalhesReservaFaturada(ID_Fluxo).CNPJ_Reserva;
            string email = servico_Empresa.RecuperarDetalhesEmpresa(cnpj).Contato.Email;

            string corpo = "SIGHO informa: Em anexo, a conta da estadia dos seguintes hóspedes:\n" +
                fluxo.Nome_1 + "  " + fluxo.RG_1 + "\n" +
                fluxo.Nome_2 + "  " + fluxo.RG_2 + "\n" +
                fluxo.Nome_3 + "  " + fluxo.RG_3 + "\n" +
                fluxo.Nome_4 + "  " + fluxo.RG_4 + "\n" +
                fluxo.Nome_5 + "  " + fluxo.RG_5 + "\n" +
                "\n\n Pagamento para até 15 dias,\nObrigado pela atenção";


            //chama o serviço que envia o email com a conta para a empresa
            return servico_Email.EnviarEmailEmpresa(email, corpo, vet);
        }

        /// <summary>
        /// Método que faz o login no CrystalReports
        /// </summary>       
        /// <param name="ArquivoReport">Reletório que ser afeito o loggin</param>
        private void LogginCrystalReports(ReportDocument ArquivoReport)
        {
            //Dados para Autenticação do CrystalReports  
            ConnectionInfo connectionInfo = new ConnectionInfo();
            connectionInfo.ServerName = ConfigurationManager.AppSettings["ServerName-Crystal"];
            connectionInfo.DatabaseName = ConfigurationManager.AppSettings["DatabaseName-Crystal"];
            connectionInfo.UserID = ConfigurationManager.AppSettings["UserID-Crystal"];
            connectionInfo.Password = ConfigurationManager.AppSettings["Password-Crystal"];

            //Faz o loggin com as informações passadas acima
            Tables tables = ArquivoReport.Database.Tables;
            TableLogOnInfo tableLogonInfo = tables[0].LogOnInfo;
            tableLogonInfo.ConnectionInfo = connectionInfo;
            tables[0].ApplyLogOnInfo(tableLogonInfo);

        }

        /// <summary>
        /// Serviço para listar todos os hospedes presentes no hotel
        /// </summary>
        /// <returns>Lista com o fluxo de hospedes do banco</returns>
        public List<Fluxo_Hospedes> RecuperarFluxoHospedes()
        {
            return repositorio.RecuperarFluxoHospedes();

        }


        /// <summary>
        /// Serviço que recupera o ID do fluxo ativo atraves de um numero de apartamento
        /// </summary>
        /// <returns>ID do fluxo</returns>
        public Fluxo_Hospedes RecuperarFluxoHospedesPorApartamento(int numero)
        {
            return repositorio.RecuperarFluxoHospedesPorApartamento(numero);

        }


        /// <summary>
        /// Verifica se a informação ja esta gravada em cache, se tiver recupera, 
        /// senao faz a consulta e grava em cache
        /// </summary>
        /// <returns>Lista de fluxo de hospedes</returns>
        public List<Fluxo_Hospedes> ListarFluxoHospedesCache()
        {
            List<Fluxo_Hospedes> fluxo_Hospedes = new List<Fluxo_Hospedes>();

            //Verifica se a informação esta guardada em cache
            if (HttpContext.Current.Cache.Get("Lista_Fluxo_Hospedes") == null)
            {
                //Consulta os hóspedes faturados no banco
                fluxo_Hospedes = RecuperarFluxoHospedes();

                //Armazena a lista de Fluxo_Hospedes em cache de 5 minutos para evitar muitas consultas ao banco
                HttpContext.Current.Cache.Add("Lista_Fluxo_Hospedes", fluxo_Hospedes, null,
                                 DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.High, null);


            }

           //caso essa informaçao ja estiver no cache
            else
            {
                //Resgata informação do cache
                fluxo_Hospedes = (List<Fluxo_Hospedes>)HttpContext.Current.Cache.Get("Lista_Fluxo_Hospedes");
            }
            return fluxo_Hospedes;
        }

        /// <summary>
        /// Serviço para listar todos os hospedes particulares presentes no hotel
        /// </summary>
        /// <returns>Lista com o fluxo de hospedes particulares do banco</returns>
        public List<Fluxo_Hospedes> RecuperarFluxoHospedesParticulares()
        {
            return repositorio.RecuperarFluxoHospedesParticulares();

        }

        /// <summary>
        /// Verifica se a informação ja esta gravada em cache, se tiver recupera, 
        /// senao faz a consulta e grava em cache
        /// </summary>
        /// <returns>Lista de fluxo de hospedes</returns>
        public List<Fluxo_Hospedes> ListarFluxoHospedesParticularesCache()
        {
            List<Fluxo_Hospedes> listaFluxoHospedesParticulares = new List<Fluxo_Hospedes>();

            //Verifica se a informação esta guardada em cache
            if (HttpContext.Current.Cache.Get("Lista_Fluxo_Hospedes_Particulares") == null)
            {
                //Consulta os hóspedes faturados no banco
                listaFluxoHospedesParticulares = RecuperarFluxoHospedesParticulares();

                //Armazena a lista de Fluxo_Hospedes em cache de 5 minutos para evitar muitas consultas ao banco
                HttpContext.Current.Cache.Add("Lista_Fluxo_Hospedes_Particulares", listaFluxoHospedesParticulares, null,
                                 DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.High, null);


            }

           //caso essa informaçao ja estiver no cache
            else
            {
                //Resgata informação do cache
                listaFluxoHospedesParticulares = (List<Fluxo_Hospedes>)HttpContext.Current.Cache.Get("Lista_Fluxo_Hospedes_Particulares");
            }
            return listaFluxoHospedesParticulares;
        }

        /// <summary>
        /// Serviço para listar todos os hospedes faturados presentes no hotel
        /// </summary>
        /// <returns>Lista com o fluxo de hospedes faturados do banco</returns>
        public List<Fluxo_Hospedes> RecuperarFluxoHospedesFaturados()
        {
            return repositorio.RecuperarFluxoHospedesFaturados();
        }

        /// <summary>
        /// Verifica se a informação ja esta gravada em cache, se tiver recupera, 
        /// senao faz a consulta e grava em cache
        /// </summary>
        /// <returns>Lista de fluxo de hospedes faturados</returns>
        public List<Fluxo_Hospedes> ListarFluxoHospedesFaturadosCache()
        {
            List<Fluxo_Hospedes> listaFluxoHospedesFaturados = new List<Fluxo_Hospedes>();

            //Verifica se a informação esta guardada em cache
            if (HttpContext.Current.Cache.Get("Lista_Fluxo_Hospedes_Faturados") == null)
            {
                //Consulta os hóspedes faturados no banco
                listaFluxoHospedesFaturados = RecuperarFluxoHospedesFaturados();

                //Armazena a lista de Fluxo_Hospedes em cache de 5 minutos para evitar muitas consultas ao banco
                HttpContext.Current.Cache.Add("Lista_Fluxo_Hospedes_Faturados", listaFluxoHospedesFaturados, null,
                                 DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.High, null);


            }

           //caso essa informaçao ja estiver no cache
            else
            {
                //Resgata informação do cache
                listaFluxoHospedesFaturados = (List<Fluxo_Hospedes>)HttpContext.Current.Cache.Get("Lista_Fluxo_Hospedes_Faturados");
            }
            return listaFluxoHospedesFaturados;
        }

        /// <summary>
        /// Serviço para listar todos os hospedes faturados presentes no hotel
        /// </summary>
        /// <returns>Lista com o fluxo de hospedes faturados do banco</returns>
        public List<Fluxo_Hospedes> RecuperarFluxoHospedesAgora()
        {
            return repositorio.RecuperarFluxoHospedesAgora();
        }

        /// <summary>
        /// Verifica se a informação ja esta gravada em cache, se tiver recupera, 
        /// senao faz a consulta e grava em cache
        /// </summary>
        /// <returns>Lista de fluxo de hospedes faturados</returns>
        public List<Fluxo_Hospedes> ListarFluxoHospedesAgoraCache()
        {
            List<Fluxo_Hospedes> listaFluxoHospedesAgora = new List<Fluxo_Hospedes>();

            //Verifica se a informação esta guardada em cache
            if (HttpContext.Current.Cache.Get("Lista_Fluxo_Hospedes_Agora") == null)
            {
                //Consulta os hóspedes presentes no banco
                listaFluxoHospedesAgora = RecuperarFluxoHospedesAgora();

                //Armazena a lista de Fluxo_Hospedes em cache de 5 minutos para evitar muitas consultas ao banco
                HttpContext.Current.Cache.Add("Lista_Fluxo_Hospedes_Agora", listaFluxoHospedesAgora, null,
                                 DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.High, null);


            }

           //caso essa informaçao ja estiver no cache
            else
            {
                //Resgata informação do cache
                listaFluxoHospedesAgora = (List<Fluxo_Hospedes>)HttpContext.Current.Cache.Get("Lista_Fluxo_Hospedes_Agora");
            }
            return listaFluxoHospedesAgora;
        }

        /// <summary>
        /// Serviço para listar todos os hospedes que já estiveram no hotel
        /// </summary>
        /// <returns>Lista com o fluxo de hospedes do banco</returns>
        public List<Fluxo_Hospedes> RecuperarFluxoHospedesAntigos()
        {
            return repositorio.RecuperarFluxoHospedesAntigos();
        }

        /// <summary>
        /// Verifica se a informação ja esta gravada em cache, se tiver recupera, 
        /// senao faz a consulta e grava em cache
        /// </summary>
        /// <returns>Lista de fluxo de hospedes</returns>
        public List<Fluxo_Hospedes> ListarFluxoHospedesAntigosCache()
        {
            List<Fluxo_Hospedes> listaFluxoHospedesAntigos = new List<Fluxo_Hospedes>();

            //Verifica se a informação esta guardada em cache
            if (HttpContext.Current.Cache.Get("Lista_Fluxo_Hospedes_Antigos") == null)
            {
                //Consulta os hóspedes presentes no banco
                listaFluxoHospedesAntigos = RecuperarFluxoHospedesAntigos();

                //Armazena a lista de Fluxo_Hospedes em cache de 5 minutos para evitar muitas consultas ao banco
                HttpContext.Current.Cache.Add("Lista_Fluxo_Hospedes_Antigos", listaFluxoHospedesAntigos, null,
                                 DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.High, null);


            }

           //caso essa informaçao ja estiver no cache
            else
            {
                //Resgata informação do cache
                listaFluxoHospedesAntigos = (List<Fluxo_Hospedes>)HttpContext.Current.Cache.Get("Lista_Fluxo_Hospedes_Antigos");
            }
            return listaFluxoHospedesAntigos;
        }

        /// <summary>
        /// Serviço para recuperar um hospede especifico presente no hotel
        /// </summary>
        /// <returns>fluxo de hospedes específico</returns>
        public Fluxo_Hospedes RecuperarDetalhesFluxoHospede(int ID)
        {
            return repositorio.RecuperarDetalhesFluxoHospede(ID);
        }

        /// <summary>
        /// Serviço para verificar se o hospede ja esta no hotel
        /// </summary>
        /// <returns>fluxo de hospedes específico</returns>
        public bool VerificarHospedeJaHotel(int ID)
        {
            Fluxo_Hospedes fluxo = repositorio.RecuperarDetalhesFluxoHospede(ID);

            if (fluxo != null && fluxo.NoHotel)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Serviço que verifica quantos hóspedes estão na reserva 
        /// </summary>
        /// <returns>quantidade de hóspede na reserva</returns
        public int QuantidadeHospedes(Fluxo_Hospedes fluxo)
        {
            int quantidade = 0;

            if (!String.IsNullOrEmpty(fluxo.Nome_1))
                quantidade++;
            if (!String.IsNullOrEmpty(fluxo.Nome_2))
                quantidade++;
            if (!String.IsNullOrEmpty(fluxo.Nome_3))
                quantidade++;
            if (!String.IsNullOrEmpty(fluxo.Nome_4))
                quantidade++;
            if (!String.IsNullOrEmpty(fluxo.Nome_5))
                quantidade++;



            return quantidade;
        }


    }
}